﻿using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ServiceCore.Tool.MongoDB
{
    public interface IMongoDB_Client<T> where T : class
    {
        /// <summary>
        /// 插入一个数据
        /// </summary>
        /// <param name="Document"></param>
        /// <returns></returns>
        void InsertItem(T Document);
        /// <summary>
        /// 插入多个数据
        /// </summary>
        /// <param name="Document"></param>
        /// <returns></returns>
        void InserMany(List<T> Documents);
        /// <summary>
        /// 搜索文档
        /// </summary>
        /// <param name="Func"></param>
        /// <returns></returns>
        List<T> Linq_Search(Expression<Func<T, bool>> where);
        /// <summary>
        /// 带时间倒序查询的搜索文档
        /// </summary>
        /// <param name="Func"></param>
        /// <returns></returns>
        List<T> Linq_Search(Expression<Func<T, bool>> where, Expression<Func<T, DateTime>> desc);
        /// <summary>
        /// 带分页的搜索文档
        /// </summary>
        /// <param name="Func"></param>
        /// <returns></returns>
        List<T> Linq_Search_PageList(Expression<Func<T, bool>> where, Expression<Func<T, DateTime>> desc, int pageNum, int pageSize);
        /// <summary>
        /// 开始更新 更新多项 只更新多个属性
        /// </summary>
        /// <param name="Filter"></param>
        /// <param name="updateDefinition"></param>
        void update(Expression<Func<T, bool>> Filter, Func<UpdateDefinitionBuilder<T>, UpdateDefinition<T>> updateDefinition);
        /// <summary>
        /// 开始更新 更新多项 builder
        /// </summary>
        /// <param name="Filter"></param>
        /// <param name="update"></param>
        void update(Expression<Func<T, bool>> Filter, Func<UpdateDefinitionBuilder<T>, List<UpdateDefinition<T>>> updateDefinition);
        /// <summary>
        ///  获取聚合结果集
        /// </summary>
        /// <param name="pipeline"></param>
        /// <returns></returns>
        IAsyncCursor<BsonDocument> GetAggregate(PipelineDefinition<T, BsonDocument> pipeline);

        /// <summary>
        /// 删除指定条件的文档
        /// </summary>
        /// <param name="Filter"></param>
        void delete(Expression<Func<T, bool>> Filter);

        IMongoCollection<T> collection { get; }
    }
    public class MongoDB_Client<T> : IMongoDB_Client<T> where T : class
    {
        private readonly IMongoDB_Config _config;
        public MongoDB_Client(IMongoDB_Config config)
        {
            _config = config;
        }

        private static IMongoCollection<T> _collection;
        public IMongoCollection<T> collection
        {
            get {
                if (_collection == null)
                {
                    _collection = _config.database.GetCollection<T>(typeof(T).Name);
                }
                return _collection;
            }
        }
        /// <summary>
        /// 插入一个数据
        /// </summary>
        /// <param name="Document"></param>
        /// <returns></returns>
        public void InsertItem(T Document)
        {
            try
            {
                 collection.InsertOne(Document); 
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 插入多个数据
        /// </summary>
        /// <param name="Document"></param>
        /// <returns></returns>
        public void InserMany(List<T> Documents)
        {
            try
            {
                 collection.InsertMany(Documents); 
            }
            catch (Exception ex)
            {
                throw ex;
            } 
        } 
        /// <summary>
        /// 搜索文档
        /// </summary>
        /// <param name="Func"></param>
        /// <returns></returns>
        public List<T> Linq_Search(Expression<Func<T, bool>> where)
        {
            try
            {
                var q = from o in collection.AsQueryable() 
                        select o;
                if (where != null)
                {
                    q = q.Where(where);
                }
                return q.ToList();
            }
            catch (Exception ex)
            {
                throw ex; 
            }
        } 
        /// <summary>
        /// 搜索文档
        /// </summary>
        /// <param name="Func"></param>
        /// <returns></returns>
        public List<T> Linq_Search(Expression<Func<T, bool>> where, Expression<Func<T, DateTime>> desc)
        {
            try
            {
                var q = from o in collection.AsQueryable()
                        select o;
                if (where != null)
                {
                    q = q.Where(where);
                }
                q = q.OrderByDescending(desc);
                return q.ToList();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 搜索文档
        /// </summary>
        /// <param name="Func"></param>
        /// <returns></returns>
        public List<T> Linq_Search_PageList(Expression<Func<T, bool>> where, Expression<Func<T, DateTime>> desc, int pageNum, int pageSize)
        {
            try
            {
                var q = from o in collection.AsQueryable()
                        select o;
                if (where != null)
                {
                    q = q.Where(where);
                }
                q = q.OrderByDescending(desc);
                q = q.Skip((pageNum - 1) * pageSize).Take(pageSize);
                return q.ToList();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 开始更新 更新多项 只更新多个属性
        /// </summary>
        /// <param name="Filter"></param>
        /// <param name="update"></param>
        public void update(Expression<Func<T, bool>> Filter, Func<UpdateDefinitionBuilder<T>, UpdateDefinition<T>> updateDefinition)
        {
            try
            {
                var updateBuilder = Builders<T>.Update;
                var result = updateDefinition(updateBuilder);
                collection.UpdateMany(Filter, result);
            }
            catch (Exception ex)
            {
                throw ex; 
            }
        }
        /// <summary>
        /// 开始更新 更新多项 builder
        /// </summary>
        /// <param name="Filter"></param>
        /// <param name="update"></param>
        public void update(Expression<Func<T, bool>> Filter, Func<UpdateDefinitionBuilder<T>, List<UpdateDefinition<T>>> updateDefinition)
        {
            try
            {
                var update = Builders<T>.Update;
                var result = updateDefinition(update);
                collection.UpdateMany(Filter, update.Combine(result));
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pipeline"></param>
        /// <returns></returns>
        public float Serch(Func<IMongoCollection<T>, float> Func)
        {
            try
            { 
                return Func(collection); 
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 聚合结果集
        /// </summary>
        /// <param name="pipeline"></param>
        /// <returns></returns>
        public IAsyncCursor<BsonDocument> GetAggregate(PipelineDefinition<T, BsonDocument> pipeline)
        {
            try
            {
                return collection.Aggregate(pipeline);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
         
        /// <summary>
        /// 根据条件删除指定项
        /// </summary>
        /// <param name="Filter"></param>
        public void delete(Expression<Func<T, bool>> Filter)
        {
            try
            {
                collection.DeleteMany(Filter);
            }
            catch (Exception ex)
            {
                throw ex; 
            }
        }
    }
}
